package com.example.myweb.Service.Auth.Impl;

import com.example.myweb.Domain.Entity.User;
import com.example.myweb.Dto.Auth.ForgotPasswordRequestDTO;
import com.example.myweb.Dto.Auth.LoginRequestDTO;
import com.example.myweb.Dto.Auth.RegisterRequestDTO;
import com.example.myweb.Dto.Auth.ResetPasswordRequestDTO;
import com.example.myweb.Dto.User.UserProfileUpdateRequestDTO;
import com.example.myweb.Exception.CustomException;
import com.example.myweb.Repository.JpaRepository.UserRepository;
import com.example.myweb.Security.JwtUtil;
import com.example.myweb.Service.Auth.AuthService;
import com.example.myweb.Vo.Auth.AuthResponseVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.UUID;

@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder; // 注入密码编码器

    @Autowired
    private AuthenticationManager authenticationManager; // Spring Security的认证管理器

    @Autowired
    private JwtUtil jwtUtil; // 注入JWT工具类

    @Override
    public AuthResponseVO register(RegisterRequestDTO request) {
        // 1. 检查邮箱是否已注册
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new CustomException("Email already registered.");
        }
        // 2. 检查手机号是否已注册 (如果提供了手机号)
        if (request.getPhoneNumber() != null && userRepository.existsByPhoneNumber(request.getPhoneNumber())) {
            throw new CustomException("Phone number already registered.");
        }

        // 3. 创建用户实体
        User newUser = new User();
        newUser.setEmail(request.getEmail());
        // 加密密码
        newUser.setPasswordHash(passwordEncoder.encode(request.getPassword())); // 调用 setPasswordHash
        newUser.setNickname(request.getNickname());
        newUser.setPhoneNumber(request.getPhoneNumber());
        // 其他默认值在User实体构造函数中设置 (registrationTime, status)

        // 4. 保存用户
        User savedUser = userRepository.save(newUser);

        // 5. 生成JWT
        String token = jwtUtil.generateToken(savedUser); // 使用User实体作为UserDetails

        return new AuthResponseVO(
                token,
                "Registration successful!",
                savedUser.getUserId(),
                savedUser.getNickname(),
                savedUser.getAvatarUrl()
        );
    }

    @Override
    public AuthResponseVO login(LoginRequestDTO request) {
        Authentication authentication;
        try {
            // 尝试认证用户
            authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword())
            );
        } catch (AuthenticationException e) {
            // 认证失败（用户名不存在或密码错误）
            throw new CustomException("Invalid email or password.");
        }

        // 认证成功后，从 Authentication 对象中获取 UserDetails
        User userDetails = (User) authentication.getPrincipal(); // 获取的是我们CustomUserDetailsService加载的User对象

        // 生成JWT
        String token = jwtUtil.generateToken(userDetails);

        return new AuthResponseVO(
                token,
                "Login successful!",
                userDetails.getUserId(), // 假设User实体有getUserId()
                userDetails.getNickname(), // 假设User实体有getNickname()
                userDetails.getAvatarUrl() // 假设User实体有getAvatarUrl()
        );
    }

    @Override
    @Transactional // 确保更新操作在事务中进行
    public User updateProfile(Long userId, UserProfileUpdateRequestDTO request) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new CustomException("User not found with ID: " + userId));

        // 根据请求体中的字段进行更新
        if (request.getNickname() != null && !request.getNickname().trim().isEmpty()) {
            user.setNickname(request.getNickname().trim());
        }
        if (request.getAvatarUrl() != null) { // 允许设置为null，表示清空头像
            user.setAvatarUrl(request.getAvatarUrl());
        }
        if (request.getBio() != null) { // 允许设置为null，表示清空简介
            user.setBio(request.getBio());
        }

        return userRepository.save(user); // 保存更新后的用户
    }

    @Override
    public void forgotPassword(ForgotPasswordRequestDTO request) {
        // 1. 根据邮箱或手机号查找用户
        Optional<User> userOptional;
        if (request.getEmailOrPhone().contains("@")) { // 简单判断是邮箱
            userOptional = userRepository.findByEmail(request.getEmailOrPhone());
        } else { // 认为是手机号
            userOptional = userRepository.findByPhoneNumber(request.getEmailOrPhone());
        }

        if (userOptional.isEmpty()) {
            // 注意：为了安全，即使用户不存在，也返回通用成功消息，避免泄露用户存在性信息
            System.out.println("用户不存在，但已发送重置说明 (模拟)");
            return;
        }

        User user = userOptional.get();

        // 2. 生成一个唯一的密码重置令牌
        String resetToken = UUID.randomUUID().toString();
        // 3. 将令牌存储到数据库或缓存中，并关联用户ID和设置过期时间
        // 建议：在User实体中添加 resetToken 和 resetTokenExpiryTime 字段，或者新建一个表
        // 为了简化，这里假设User实体有这些字段
        user.setResetToken(resetToken);
        user.setResetTokenExpiryTime(LocalDateTime.now().plusHours(1)); // 令牌1小时内有效
        userRepository.save(user);

        // 4. 发送邮件或短信
        // 实际应用中，这里需要集成邮件服务或短信服务
        // 例如：emailService.sendPasswordResetEmail(user.getEmail(), resetToken);
        System.out.println("--- 模拟邮件/短信发送 ---");
        System.out.println("已向 " + request.getEmailOrPhone() + " 发送密码重置链接/验证码。");
        System.out.println("重置令牌: " + resetToken);
        System.out.println("-------------------------");
    }

    @Override
    @Transactional
    public void resetPassword(ResetPasswordRequestDTO request) {
        // 1. 根据令牌查找用户
        // 假设 User 实体有 resetToken 字段
        User user = userRepository.findByResetToken(request.getToken())
                .orElseThrow(() -> new CustomException("无效或已过期的重置令牌。"));

        // 2. 检查令牌是否过期
        if (user.getResetTokenExpiryTime() == null || user.getResetTokenExpiryTime().isBefore(LocalDateTime.now())) {
            // 清除过期的令牌
            user.setResetToken(null);
            user.setResetTokenExpiryTime(null);
            userRepository.save(user);
            throw new CustomException("重置令牌已过期，请重新申请。");
        }

        // 3. 更新密码
        user.setPasswordHash(passwordEncoder.encode(request.getNewPassword())); // 哈希新密码
        user.setResetToken(null); // 清除已使用的令牌
        user.setResetTokenExpiryTime(null); // 清除令牌过期时间
        userRepository.save(user);
    }
    @Override
    @Transactional // 推荐为所有写操作添加事务注解
    public void updatePassword(Long userId, String oldPassword, String newPassword) {
        // 1. 根据ID找到用户，如果找不到则抛出异常
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new CustomException("用户不存在", HttpStatus.NOT_FOUND));

        if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            throw new CustomException("原密码不正确", HttpStatus.BAD_REQUEST);
        }

        if (passwordEncoder.matches(newPassword, user.getPassword())) {
            throw new CustomException("新密码不能与旧密码相同", HttpStatus.BAD_REQUEST);
        }

        // --- 这是关键的修改 ---
        // 调用 User 类中实际存在的方法 setPasswordHash()
        user.setPasswordHash(passwordEncoder.encode(newPassword));
        // 5. 保存更新后的用户信息
        // 因为有 @Transactional 注解，这一步可以省略，事务提交时会自动保存
        // userRepository.save(user);
    }
}